package com.myidis.servlet;

import java.util.ArrayList;
import java.util.ArrayList;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.auxiliary.BBForPeakValley;
import com.auxiliary.BasicCalculator;
import com.auxiliary.CorrelationLine;
import com.auxiliary.Inflexion;
import com.auxiliary.KLInformation;
import com.auxiliary.PeakValleyCalculator;
import com.auxiliary.QuotaDataFinder;
import com.auxiliary.SeasonAdjuster;
import com.auxiliary.TimeCorrelation;
import com.auxiliary.TimeSequence;
import com.myidis.entity.AnalysisResult;
import com.myidis.entity.QuotaData;
import com.myidis.mapper.AnalysisResultMapper;
import com.myidis.mapper.QuotaDataMapper;
import com.myidis.mapper.QuotaMapper;
import com.myidis.request.CorrelationReq;
import com.myidis.request.PeakValleyReq;
import com.myidis.request.CheckReq;
import com.myidis.request.BBReq;
import com.myidis.request.SeasonAdjustReq;
import com.myidis.response.BBRes;
import com.myidis.response.CorrelationRes;
import com.myidis.response.PeakValleyRes;
import com.myidis.response.SeasonAdjustRes;
import com.myidis.response.StatisticsRes;

@Service
public class AnalysisServlet {
	@Autowired
	private QuotaMapper quotaMapper;
	@Autowired
	private QuotaDataMapper quotaDataMapper;
	@Autowired
	private AnalysisResultMapper anaResMapper;
	
	/*
	 * 检查数据的完整性，若完整返回1，否则返回null
	 * @param CheckReq
	 * @return Integer
	 */
	public Integer check(CheckReq req) {
		//若指标数组为空或没有数据，返回null
		if(req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//对所有分析指标进行完整性检查，不需要进行季节调整，若都完整则返回1，否则返回null
		if(checkListIntegrality(req, false) != null)
			return 1;
		else
			return null;
	}
	
	/*
	 * 计算基本统计量，计算前先检查数据完整性，若不完整，返回null
	 * @param CheckReq
	 * @return ArrayList<StatisticsRes>
	 */
	public ArrayList<StatisticsRes> statistics(CheckReq req) {
		//若指标数组为空或没有数据，返回null
		if(req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//建立时间序列类TimeSequence集合，并进行数据完整性检查，不需要进行季节调整
		ArrayList<TimeSequence> sequenceList = checkListIntegrality(req, false);
		
		//若时间序列集合为null，说明数据完整性检查不通过，返回null
		if(sequenceList == null)
			return null;
		
		//建立计算类BasicCalculator对象
		BasicCalculator bc = new BasicCalculator();
		
		//建立基本统计量结果类集合List<StatisticsRes>
		ArrayList<StatisticsRes> ArrayList = new ArrayList<StatisticsRes>();
		
		//对每个指标进行基本统计量计算
		for(TimeSequence sequence: sequenceList) {
			
			double max = bc.getMax(sequence.getValueList());
			double min = bc.getMin(sequence.getValueList());
			double avg = bc.calcAvg(sequence.getValueList());;
			double stdev = bc.calcStdev(sequence.getValueList());
			double mid = bc.calcMedian(sequence.getValueList());
			double kurtosis = bc.calcKurtosis(sequence.getValueList());
			double skewness = bc.calcSkewness(sequence.getValueList());
			
			ArrayList.add(new StatisticsRes(max, min, avg, stdev, mid, kurtosis, skewness));
		}
		
		//返回结果
		return ArrayList;
	}
	
	/*
	 * 进行季节调整，调整前先检查数据完整性，若不完整，返回null
	 * @param SeasonAdjustReq
	 * @return SeasonAdjustRes
	 */
	public SeasonAdjustRes seasonAdjust(SeasonAdjustReq req) {
		//若指标id为0，说明数据错误，返回null
		if(req.getQuota() == 0)
			return null;
		
		//进行数据完整性检查
		TimeSequence sequence = checkIntegrality(new QuotaDataFinder(req.getQuota(), req));
		//若不通过返回null
		if(sequence == null)
			return null;
		
		//进行季节调整
		SeasonAdjuster adjust = new SeasonAdjuster(sequence, req.getFrequency(), 1);
		
		//返回季节调整后序列
		return new SeasonAdjustRes(req.getCheckBox(), adjust);
	}
	
	/*
	 * 进行相关性分析，计算前先检查数据完整性，若不完整，返回null
	 * @param CorrelationReq
	 * @return CorrelationRes
	 */
	public CorrelationRes correlation(CorrelationReq req) {
		//若基准指标或分析指标数组为空或没有数据，返回null
		if(req.getBaseQuota() == null || req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//对基准指标进行数据完整性检查
		TimeSequence baseSequence = checkIntegrality(new QuotaDataFinder(req.getBaseQuota(), req));
		//若不通过则返回null
		if(baseSequence == null)
			return null;	
		
		//建立时间序列类TimeSequence集合，并进行数据完整性检查，并按情况进行季节调整进行季节调整
		ArrayList<TimeSequence> analysisSequence = checkListIntegrality(req, req.isSeasonAdjust());
		
		//若需要进行季节调整，对基准指标进行季节调整
		if(req.isSeasonAdjust()){
			SeasonAdjuster adjust = new SeasonAdjuster(baseSequence, req.getFrequency(), 1);	
			baseSequence.setValueList(adjust.getTCList());
		}
		
		//创建相关性结果类CorrelationRes
		CorrelationRes res = new CorrelationRes();
		
		//创建指标名称集合
		ArrayList<String> lineNames = new ArrayList<String>();
		
		//对各个指标进行相关性分析
		for(TimeSequence analysis: analysisSequence) {
			//获取指标名称，并添加到集合
			String quotaName = quotaMapper.getOne(analysis.getQuota()).getChineseName();
			lineNames.add(quotaName);
			
			//通过用户提交信息判断进行何种相关性分析
			for(int type: req.getCheckBox()) {
				//若为1进行时差相关性分析，否则进行KL信息量分析
				if(type == 1) {
					//时差相关性分析
					CorrelationLine timeLine = TimeCorrelation.calc(baseSequence.getValueList(), analysis.getValueList());
					//设置时差相关性图形对应的指标名称，并把结果存入返回类中
					timeLine.setName(quotaName);
					res.getTimeLineList().add(timeLine);
					
					//保存分析结果
					anaResMapper.insert(new AnalysisResult(baseSequence.getQuota(), analysis.getQuota(), 1, req.getStartTime(), req.getEndTime(), timeLine.toString(), 1));
				}
				else {
					//KL信息量分析
					CorrelationLine klLine = KLInformation.calc(baseSequence.getValueList(), analysis.getValueList());
					//设置KL信息量图形对应的指标名称，把结果存入返回类中
					klLine.setName(quotaName);
					res.getKlLineList().add(klLine);
					
					//保存分析结果
					anaResMapper.insert(new AnalysisResult(baseSequence.getQuota(), analysis.getQuota(), 2, req.getStartTime(), req.getEndTime(), klLine.toString(), 1));
				}
			}
						
			
		}
		//为返回类配置指标名称集合
		res.setLineNames(lineNames);
		
		return res;
	}
	
	/*
	 * 进行谷峰图形绘制，计算前先检查数据完整性，若不完整，返回null
	 * @param BBReq
	 * @return ArrayList<BBRes>
	 */
	public ArrayList<BBRes> calcBB(BBReq req) {
		//若基准指标或分析指标数组为空或没有数据，返回null
		if(req.getBaseQuota() == null || req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//对基准指标进行数据完整性检查
		TimeSequence baseSequence = checkIntegrality(new QuotaDataFinder(req.getBaseQuota(), req));
		//若不通过则返回null
		if(baseSequence == null)
			return null;	
		
		//建立时间序列类TimeSequence集合，并进行数据完整性检查，并按情况进行季节调整进行季节调整
		ArrayList<TimeSequence> analysisSequence = checkListIntegrality(req, req.isSeasonAdjust());
		
		//若需要进行季节调整，对基准指标进行季节调整
		if(req.isSeasonAdjust()){
			SeasonAdjuster adjust = new SeasonAdjuster(baseSequence, req.getFrequency(), 1);	
			baseSequence.setValueList(adjust.getSAList());
		}
		
		ArrayList<BBRes> res = new ArrayList<BBRes>();
		//计算基准指标的峰谷
		BBForPeakValley bb = new BBForPeakValley(baseSequence, req.getHalfPeriod(), req.getOnePeriod());
		res.add(bb.calc());
		
		//计算各分析指标的峰谷
		for(TimeSequence analysis: analysisSequence) {
			bb = new BBForPeakValley(analysis, req.getHalfPeriod(), req.getOnePeriod());
			
			BBRes temp = bb.calc();
			res.add(temp);
		}
		
		return res;
	}
	
	/*
	 * 进行谷峰图形分析
	 * @param PeakValleyReq
	 * @return ArrayList<String>
	 */
	public ArrayList<String> calcPeakValley(PeakValleyReq req) {
		//结果字符串
		ArrayList<String> res = new ArrayList<String>();
		
		int i = 0;
		
		//根据所给拐点（峰或谷）进行分析
		for(ArrayList<Inflexion> anaInfx: req.getAnasInfx()) {
			PeakValleyRes temp = PeakValleyCalculator.Calculate(req.getBaseInfx(), anaInfx);
			
			res.add(temp.toString());
			
			anaResMapper.insert(new AnalysisResult(req.getBaseQuota(), req.getAnalysisQuota()[i], 2, req.getStartTime(), req.getEndTime(), temp.toString(), 1));
			i++;
		}
		
		return res;
	}
	
	//复合一致指标
	public ArrayList<Double> comcQuota(SeasonAdjustReq req) {
		TimeSequence sequence = checkIntegrality(new QuotaDataFinder(req.getQuota(), req));
		
		if(sequence == null)
			return null;
		
		SeasonAdjuster adjust = new SeasonAdjuster(sequence, req.getFrequency(), 1);
		
		
		return null;
	}
	
	/*
	 * 检查一个指标数据的完整性，不完整返回null，否则返回时间序列类TimeSequence
	 * @param QuotaDataFinder
	 * @return TimeSequence
	 */
	public TimeSequence checkIntegrality(QuotaDataFinder check) {
		BasicCalculator bc = new BasicCalculator();
		
		int count = bc.getDataCount(check.getStartTime(), check.getEndTime());
		
		ArrayList<QuotaData> temp = quotaDataMapper.getByQuotaWithOther(check);
		TimeSequence dataList = new TimeSequence(temp);
		
		if(dataList.getDataCount() == count)
			return dataList;
		else
			return null;
	}
	
	/*
	 * 检查一组指标数据的完整性，不完整返回null，否则返回时间序列类集合List<TimeSequence>
	 * @param CheckReq
	 * @return ArrayList<TimeSequence>
	 */
	public ArrayList<TimeSequence> checkListIntegrality(CheckReq req, boolean seasonAdjust) {
		//建立时间序列类TimeSequence集合，用于存储完整性检查通过的时间序列
		ArrayList<TimeSequence> sequenceList = new ArrayList<TimeSequence>();
		
		//通过循环遍历指标数组进行完整性检查
		for(int id: req.getAnalysisQuota()) {
			
			//检查指标analysis的数据完整性
			TimeSequence temp = checkIntegrality(new QuotaDataFinder(id, req));
			
			//若返回为null，证明数据不完整，直接返回null
			if(temp == null)
				return null;
			
			//若需要进行季节调整，则对该指标进行季节调整
			if(seasonAdjust){
				SeasonAdjuster adjust = new SeasonAdjuster(temp, req.getFrequency(), 1);	
				temp.setValueList(adjust.getTCList());
			}
			
			//若检查通过，则添加到集合中
			sequenceList.add(temp);
		}
		
		//若所有指标完整性检查都通过，则返回时间序列集合
		return sequenceList;
	}
}

